package net.tv90.volunteerserveradmin.service;

import cn.dev33.satoken.stp.StpUtil;
import jakarta.annotation.Resource;
import jakarta.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
import net.tv90.volunteerserveradmin.dao.TeacherRepository;
import net.tv90.volunteerserveradmin.dao.UserRepository;
import net.tv90.volunteerserveradmin.exception.ServiceException;
import net.tv90.volunteerserveradmin.model.domain.Student;
import net.tv90.volunteerserveradmin.model.domain.Teacher;
import net.tv90.volunteerserveradmin.model.domain.User;
import net.tv90.volunteerserveradmin.model.dto.TeacherDTO;
import net.tv90.volunteerserveradmin.model.dto.TeacherQueryDTO;
import net.tv90.volunteerserveradmin.model.vo.StudentVO;
import net.tv90.volunteerserveradmin.utils.RedisUtils;
import net.tv90.volunteerserveradmin.utils.entity.PageResult;
import net.tv90.volunteerserveradmin.model.vo.TeacherVO;
import net.tv90.volunteerserveradmin.utils.entity.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TeacherService {

    @Resource
    private TeacherRepository teacherRepository;
    @Resource
    private UserRepository userRepository;
    @Resource
    private RedisUtils redisUtils;

    public TeacherVO getTeacherById(Long id) {
        Teacher teacher = teacherRepository.findById(id)
                .orElseThrow(() -> new ServiceException("教师不存在", HttpStatus.OK));
        User user = userRepository.findById(Objects.requireNonNullElse(teacher.getUserId(), -1L))
                .orElse(User.newUser());
        return new TeacherVO(teacher, user);
    }

    public List<TeacherVO> getAllTeachers() {
        List<Teacher> teachers = teacherRepository.findAll();
        return teachers.stream()
                .map(teacher -> {
                    User user = userRepository.findById(Objects.requireNonNullElse(teacher.getUserId(), -1L))
                            .orElse(User.newUser());
                    return new TeacherVO(teacher, user);
                })
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void addTeacher(TeacherDTO teacherDTO) {
        Assert.assertNotNull("教师信息不能为空", HttpStatus.OK, teacherDTO);
        Teacher teacher = new Teacher();
        BeanUtils.copyProperties(teacherDTO, teacher);
        teacherRepository.save(teacher);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateTeacher(Long id, TeacherDTO teacherDTO) {
        Teacher teacher = teacherRepository.findById(id)
                .orElseThrow(() -> new ServiceException("教师不存在", HttpStatus.OK));
        BeanUtils.copyProperties(teacherDTO, teacher);
        teacherRepository.save(teacher);
        deleteTeacherCache(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteTeacher(Long id) {
        Teacher teacher = teacherRepository.findById(id)
                .orElseThrow(() -> new ServiceException("教师不存在", HttpStatus.OK));
        User user = userRepository.findById(Objects.requireNonNullElse(teacher.getUserId(), -1L)).orElse(null);
        if(user != null) {
            throw new ServiceException("该教师已绑定用户" + user.getUsername() + "，无法删除");
        }
        teacherRepository.delete(teacher);
        deleteTeacherCache(id);
    }

    public PageResult<TeacherVO> queryTeacher(TeacherQueryDTO dto) {
        // 设置默认分页参数
        if (dto.getPage() == null || dto.getPage() < 1) {
            dto.setPage(1);
        }
        if (dto.getPageNum() == null || dto.getPageNum() < 10 || dto.getPageNum() > 100) {
            dto.setPageNum(10);
        }
        if (dto.getOrderBy() == null || dto.getOrderBy().isEmpty()) {
            dto.setOrderBy("id");
        }
        if (dto.getDesc() == null) {
            dto.setDesc(0);
        }

        // 构建排序规则
        Sort sort = dto.getDesc() == 1 ? Sort.by(dto.getOrderBy()).descending() : Sort.by(dto.getOrderBy()).ascending();
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageNum(), sort);

        // 构建 Specification
        Specification<Teacher> spec = (root, query, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();

            // 根据工号过滤
            if (dto.getStaffNumber() != null && !dto.getStaffNumber().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("staffNumber"), dto.getStaffNumber()));
            }

            // 根据姓名过滤
            if (dto.getName() != null && !dto.getName().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("name"), "%" + dto.getName() + "%"));
            }

            // 根据身份证号过滤
            if (dto.getIdCardNumber() != null && !dto.getIdCardNumber().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("idCardNumber"), dto.getIdCardNumber()));
            }

            // 根据性别过滤
            if (dto.getGender() != null && !dto.getGender().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("gender"), dto.getGender()));
            }

            // 根据出生日期过滤
            if (dto.getDateOfBirth() != null) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("dateOfBirth"), dto.getDateOfBirth()));
            }

            // 根据院系过滤
            if (dto.getDepartment() != null && !dto.getDepartment().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("department"), "%" + dto.getDepartment() + "%"));
            }

            // 根据职位过滤
            if (dto.getPosition() != null && !dto.getPosition().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("position"), "%" + dto.getPosition() + "%"));
            }

            // 根据地址过滤
            if (dto.getAddress() != null && !dto.getAddress().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("address"), "%" + dto.getAddress() + "%"));
            }

            return predicate;
        };

        // 查询并返回分页结果
        Page<Teacher> teacherPage = teacherRepository.findAll(spec, pageRequest);

        // 将查询结果转换为 TeacherVO
        List<TeacherVO> list = teacherPage.getContent().stream()
                .map(teacher -> {
                    User user = userRepository.findById(Objects.requireNonNullElse(teacher.getUserId(), -1L))
                            .orElse(User.newUser());
                    return new TeacherVO(teacher, user);
                })
                .collect(Collectors.toList());

        return new PageResult<>(list, teacherPage.getTotalElements());
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchAddTeachers(List<TeacherDTO> teacherDTOList) {
        List<Teacher> teachers = teacherDTOList.stream().map(dto -> {
            Teacher teacher = new Teacher();
            BeanUtils.copyProperties(dto, teacher);
            return teacher;
        }).collect(Collectors.toList());
        teacherRepository.saveAll(teachers);
    }

    public void deleteTeacherCache(Long id) {
        String redisUserKey = "teacher::status::" + id;
        redisUtils.deleteObject(redisUserKey);
    }

    public TeacherVO getTeacherSelfById(Long teacherId) {
        Long userId = StpUtil.getLoginIdAsLong();
        Teacher teacher = teacherRepository.findById(teacherId)
                .orElseThrow(() -> new ServiceException("教师不存在", HttpStatus.OK));
        if(!Objects.equals(userId, teacher.getUserId())) {
            throw new ServiceException("无法查看他人信息！");
        }
        User user = userRepository.findById(teacher.getUserId())
                .orElse(User.newUser());
        return new TeacherVO(teacher, user);
    }
}
